/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sudoku;

import java.util.ArrayList;

/**
 *
 * @author kaaz
 */
public class Sudoku implements SudokuImplementation{

    public boolean solved = false;
    public int[][] actualBoard;
    private ArrayList <Integer>[][] PossibleOptions;
    public final int DEFAULT_BOARD_SIZE = 9;
    public int BOARD_SIZE;
    public int BOX_SIZE;
    
    Sudoku(){
	setBoardOptions(DEFAULT_BOARD_SIZE);
    }
    public Integer[][] getSolution(){
	this.solve(0,0);
	Integer[][] temp = new Integer[BOARD_SIZE][BOARD_SIZE];
	for(int i=0;i<actualBoard.length;i++){
	    for(int j=0;j<actualBoard[i].length;j++){
		temp[i][j] = actualBoard[i][j];
	    }   
	}
	return temp;
    }
    
    public void setboard(Integer[][] newboard){
	this.actualBoard = new int[BOARD_SIZE][BOARD_SIZE];
	this.PossibleOptions = new ArrayList[BOARD_SIZE+1][BOARD_SIZE+1];
	for(int i=0;i<BOARD_SIZE;i++){
	    for(int j=0;j<BOARD_SIZE;j++){
		if(newboard[i][j] != null){
		    this.actualBoard[i][j] = newboard[i][j];
		}
		else{
		    this.actualBoard[i][j]=0;
		}
		PossibleOptions[i][j] = new ArrayList<>();
	    }   
	}
	for(int i=0;i<BOARD_SIZE;i++){
	    for(int j=0;j<BOARD_SIZE;j++){
		for (int e = 1; e <= BOARD_SIZE; e++) {
		    if(checkPossible(i, j, (int) e)){
			PossibleOptions[i][j].add(e);
		    }
                }
	    }
	}
    }
    
    public void setBoardOptions(int size){
	BOX_SIZE = (int) Math.sqrt( (double) size);
	if(BOX_SIZE * BOX_SIZE != size){
	    setBoardOptions(DEFAULT_BOARD_SIZE);
	}else{
	    BOARD_SIZE = size;
	    solved=false;
	    System.out.println("Board Options:");
	    System.out.println("Size: " + BOARD_SIZE);
	    System.out.println("grid size:"+BOX_SIZE+"x"+BOX_SIZE);
	    if(BOARD_SIZE != DEFAULT_BOARD_SIZE){
		resetboard();
	    }
	}
    }
    public void resetboard(){
	actualBoard = new int[BOARD_SIZE][BOARD_SIZE];
	PossibleOptions = null;
	solved = false;
    }
    private boolean checkPossible(int row, int col, int n) {

	int gridRow = row - (row % BOX_SIZE);
	int gridCol = col - (col % BOX_SIZE);
	for (int c = 0; c < BOARD_SIZE; c++) {
	    if (actualBoard[row][c] == n) {
		return false;
	    }
	}
	for (int r = 0; r < BOARD_SIZE; r++) {
	    if (actualBoard[r][col] == n) {
		return false;
	    }
	}
	for (int i = 0; i < BOX_SIZE; i++) {
	    for (int j = 0; j < BOX_SIZE; j++) {
		if (actualBoard[gridRow + i][gridCol + j] == n) {
		    return false;
		}
	    }
	}
	return true;
    }

    public void solve(int row, int col) {
	if (col == BOARD_SIZE) {
	    col = 0;
	    row++;
	}
	if (row == BOARD_SIZE) {
	    solved = true;
	    return;
	}
	if (actualBoard[row][col] == 0) {
	    for(Integer number : PossibleOptions[row][col]){
		if (checkPossible(row, col, number) && !solved) {
		    actualBoard[row][col] = number;
		    solve(row, col + 1);
		}
	    }
	    if (!solved) {
		actualBoard[row][col] = 0;
	    }
	} else {
	    solve(row, col + 1);
	}
    }
    @Override
    public void goButtonPressed(Integer[][] leftSudokuValues, SudokuController resultAcceptor) {
	
	resultAcceptor.setSudokuCompleted(false);
	resetboard();
	setboard((leftSudokuValues));
	resultAcceptor.setSudokuResult(getSolution());
	resultAcceptor.setSudokuCompleted(this.solved);
        System.out.println("Done!");
    }
}
